namespace music {
	export class Music {
		file: string;

		loop: number;

		volume = 0.3;

		sound: egret.Sound;

		channel: egret.SoundChannel;

		isPlaying(): boolean {
			return this.channel != null;
		}

		play(pos = 0): void {
			if (!this.sound) {
				return;
			}
			const loop = pos === 0 && this.loop;
			this.channel = this.sound.play(pos, loop ? 0 : 1);
			// console.log("sound.play",this.file,this.loop,pos)
			this.channel.volume = this.volume;
			if (!this.loop) {
				this.channel.addEventListener(egret.Event.SOUND_COMPLETE, this.onComplete, this);
			}
			if (!loop && this.loop) {
				// pos != 0
				this.channel.addEventListener(egret.Event.SOUND_COMPLETE, this.onPlayAgain, this);
			}
		}

		onPlayAgain(): void {
			this.play();
		}

		posPause = 0;

		stop(): number {
			// console.log("stop()",this.channel != null)
			let stopPos = 0;
			if (this.channel) {
				stopPos = this.channel.position;
				this.channel.stop();
				this.channel = null;
			}
			return stopPos;
		}

		pause(): void {
			// console.log("pause",this.is_playing())
			if (!this.isPlaying()) {
				return;
			}
			this.posPause = this.stop();
		}

		resume(): void {
			if (this.isPlaying()) {
				return;
			}
			if (this.sound) {
				this.play(this.posPause);
			}
		}

		onComplete(): void {
			this.channel = null;
		}

		onActive(): void {
			this.resume();
		}

		onDeactive(): void {
			this.pause();
		}

		setVolume(vol: number): void {
			this.volume = vol;
			this.pause();
			this.resume();
		}
	}

	export class BaseMusic extends Music {
		onMusicon(obj: any, on: boolean): void {
			if (on) {
				this.onActive();
			} else {
				this.stop();
			}
		}

		musicno: number;

		playMp3(musicno: number): void {
			if (musicno === this.musicno) {
				return;
			}
			this.stop();
			this.musicno = musicno;
			this.posPause = 0;
			if (!musicno) {
				return;
			}
			this.playNo();
		}

		release(): void {
			if (this.sound) {
				ResMgr.ins().unref(this.file, 'music');
				this.sound = null;
			}
		}

		loadindex = 0;

		async playMusic(file: string, loop: number): Promise<void> {
			console.log('playMusic', file, this.volume, loop);
			// this.volume = vol;
			this.loop = loop;

			if (file === this.file) {
				if (!this.isPlaying()) {
					this.play();
				}
				return;
			}

			if (this.isPlaying()) {
				this.stop();
				Sounds.ins().findSound(this.file); // update cache..
			}
			// this.sound = null
			this.release();
			this.file = file;

			this.loadindex++;
			const index = this.loadindex;
			const sound = await Sounds.ins().getSound(this.file);
			if (sound && index === this.loadindex) {
				// play the last one!
				this.sound = sound;
				ResMgr.ins().ref(this.file, 'music');
				this.play();
			} else if (sound) {
				// sound.Release?
			}
		}

		playNo(): void {
			if (!this.musicno) {
				return;
			}

			if (gamedata.Setting.ins().isMusicon()) {
				const file = `music/${miscUtils.stringPad(this.musicno, 4)}.mp3`;
				this.playMusic(file, 1);
				// this.play();
			}
		}

		override onActive(): void {
			if (!this.isPlaying()) {
				if (this.sound) {
					this.resume();
				} else {
					this.playNo();
				}
			}
		}
	}

	export class BgMusic extends BaseMusic {
		private static instance: BgMusic;

		public static ins(): BgMusic {
			if (!this.instance) {
				this.instance = new BgMusic();
			}
			return this.instance;
		}

		constructor() {
			super();
			gamedata.Setting.ins().on('musicon', this.onMusicon, this, 'bgmusic');
		}
	}

	export class WeathMusic extends BaseMusic {
		private static instance2: WeathMusic;

		public static ins(): WeathMusic {
			if (!this.instance2) {
				this.instance2 = new WeathMusic();
			}
			return this.instance2;
		}

		constructor() {
			super();
			gamedata.Setting.ins().on('musicon', this.onMusicon, this, 'WeathMusic');
		}

		weather: string;

		setWeather(weather: string): void {
			this.weather = weather;
			this.playNo();
		}

		override playNo(): void {
			if (!this.weather) {
				return;
			}

			if (gamedata.Setting.ins().isMusicon()) {
				const file = `music/${this.weather}.mp3`;
				this.playMusic(file, 1);
			}
		}

		override stop(): number {
			this.weather = '';
			return super.stop();
		}
	}

	export function playBg(musicno: number): void {
		// console.log("play_bg", musicno)
		if (!musicno) {
			return;
		}
		BgMusic.ins().playMp3(musicno);
	}
}
